package com.block.sms.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.common.annotate.ExceptionLog;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.constant.SmsConstant;
import com.block.common.util.StringUtil;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.SmsConfigInfo;
import com.block.db.entity.SmsRecord;
import com.block.db.entity.SmsTemplate;
import com.block.db.mapper.SmsRecordMapper;
import com.block.db.util.IdTypeEnum;
import com.block.db.util.SnowflakeUtil;
import com.block.sms.dto.SmsResultDTO;
import com.block.sms.enums.UseTypeEnum;
import com.block.sms.service.ISmsConfigInfoService;
import com.block.sms.service.ISmsRecordService;
import com.block.sms.service.ISmsTemplateService;
import com.block.sms.service.factory.SmsFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * 
 * @since 2021-02-16
 */
@Slf4j
@Service
public class SmsRecordServiceImpl extends ServiceImpl<SmsRecordMapper, SmsRecord> implements ISmsRecordService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ISmsTemplateService smsTemplateService;
    @Autowired
    ISmsConfigInfoService smsConfigInfoService;

    /**
     * 发送验证码类短信
     *
     * @param mobile
     * @param operationType
     * @return
     */
    @Override
    public ResponseVo sendSmsCode(String mobile, String operationType, String ip, String appCode) {

        String code = StringUtil.getNumByLength(6);

        UseTypeEnum verifyType = UseTypeEnum.VERIFY;

        JSONArray paramArr = new JSONArray();
        paramArr.add(code);

        ResponseVo responseVo = this.sendSms(verifyType, mobile, operationType, paramArr, ip, appCode);
        //redis记录操作类型和验证码
        if (!AppRspCodeConstant.SUCCESS.equals(responseVo.getRspCode())) {
            return responseVo;
        }
        String mobileStr = SecureUtil.md5(mobile).toLowerCase();
        stringRedisTemplate.opsForValue().set(SmsConstant.getCodeKey(operationType, mobileStr), code, SmsConstant.CODE_EXPRIES, TimeUnit.SECONDS);
        String codeCountKey = SmsConstant.getCodeCountKey(operationType, mobileStr);
        stringRedisTemplate.opsForValue().increment(codeCountKey);
        if (stringRedisTemplate.hasKey(codeCountKey)) {
            stringRedisTemplate.expire(codeCountKey, 1L, TimeUnit.DAYS);
        }
        return responseVo;
    }

    /**
     * 发送带参数的短信
     *
     * @param mobile
     * @param operationType
     * @return
     */
    @Override
    @ExceptionLog(bizName = "短信发送", bizType = "smsSendType", key = "#appCode")
    public ResponseVo sendSms(UseTypeEnum useTypeEnum, String mobile, String operationType, JSONArray paramArray, String ip, String appCode) {

        SmsTemplate smsTemplate = smsTemplateService.getAbleSmsTemplate(operationType, appCode);
//        SmsTemplate smsTemplate = smsTemplateService.getSmsTemplate("DANMI", operationType, appCode);
        SmsConfigInfo smsConfigInfo = smsConfigInfoService.getAbleInfoByUseTypeAndPlatform(useTypeEnum, smsTemplate.getPlatform());

        String outId = SnowflakeUtil.getSnowflakeByDate(IdTypeEnum.COMMON,30);
        //保存smsRecord
        SmsRecord smsRecord = saveSmsRecord(mobile, operationType, JSON.toJSONString(paramArray), smsTemplate, smsConfigInfo.getPlatform(), ip, outId);
        if (smsRecord == null) {
            log.error("【发送短信】保存短信发送记录错误");
            return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "系统繁忙，数据保存异常", outId);
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("paramArr", paramArray);

        //发送短信验证码
        SmsResultDTO smsResult = SmsFactory.getService(smsConfigInfo.getPlatform()).sendSms(mobile, outId, smsTemplate, smsConfigInfo, jsonObject);

        // 异步更新短信发送结果
//        ((ISmsRecordService) AopContext.currentProxy()).updateSmsRecord(smsRecord, smsResult);
        this.updateSmsRecord(smsRecord, smsResult);

        if (AppRspCodeConstant.SUCCESS.equals(smsResult.getCode())) {
            return new ResponseVo(AppRspCodeConstant.SUCCESS, "短信验证码发送成功，请注意查收","");
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "短信发送失败！请稍后重试" , outId);
    }



    /**
     * 发送带参数的短信
     *
     * @param mobile
     * @return
     */
    @Override
    @ExceptionLog(bizName = "短信发送模板", bizType = "smsSendType", key = "#templateId")
    public ResponseVo sendSmsTemplate(UseTypeEnum useTypeEnum, String mobile, String templateId, JSONArray paramArray, String ip) {

        SmsTemplate smsTemplate = smsTemplateService.getById(templateId);
        SmsConfigInfo smsConfigInfo = smsConfigInfoService.getAbleInfoByUseTypeAndPlatform(useTypeEnum, smsTemplate.getPlatform());

        String outId = SnowflakeUtil.getSnowflakeByDate(IdTypeEnum.COMMON,30);
        //保存smsRecord
        SmsRecord smsRecord = saveSmsRecord(mobile, String.valueOf(smsTemplate.getOtype()), JSON.toJSONString(paramArray), smsTemplate, smsConfigInfo.getPlatform(), ip, outId);
        if (smsRecord == null) {
            log.error("【发送短信】保存短信发送记录错误");
            return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "系统繁忙，数据保存异常", outId);
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("paramArr", paramArray);

        //发送短信验证码
        SmsResultDTO smsResult = SmsFactory.getService(smsConfigInfo.getPlatform()).sendSms(mobile, outId, smsTemplate, smsConfigInfo, jsonObject);

        // 异步更新短信发送结果
        this.updateSmsRecord(smsRecord, smsResult);
        if (AppRspCodeConstant.SUCCESS.equals(smsResult.getCode())) {
            return new ResponseVo(AppRspCodeConstant.SUCCESS, "短信验证码发送成功，请注意查收","");
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "短信发送失败！请稍后重试" , outId);
    }

    @Async
    @Override
    public void updateSmsRecord(SmsRecord smsRecord, SmsResultDTO smsResult){
        smsRecord.setErrorCode(smsResult.getCode());
        smsRecord.setErrorMsg(smsResult.getMessage());
        smsRecord.setRequestId(smsResult.getRequestId());
        smsRecord.setBizId(smsResult.getBizId());
        smsRecord.setHttpStatus(smsResult.getHttpStatus());

        if (AppRspCodeConstant.SUCCESS.equals(smsResult.getCode())) {
            smsRecord.setIssuccess(true);
        }else{
            smsRecord.setIssuccess(false);
        }
        boolean updateFlag = updateById(smsRecord);
        log.info("【sms更新smsRecord结果：】{}【sms更新smsRecord结果：】{}", updateFlag, smsResult.getCode() + "：" + smsResult.getMessage());
    }

    /**
     * 保存并返回id
     *
     * @param mobile
     * @param operationType
     * @param paramJson
     * @param smsTemplate
     * @param platform
     * @return
     */
    private SmsRecord saveSmsRecord(String mobile, String operationType, String paramJson, SmsTemplate smsTemplate, String platform, String ip, String outId) {
        SmsRecord smsRecord = new SmsRecord();
        smsRecord.setInterfaceType(platform);
        smsRecord.setMobile(mobile);
        smsRecord.setOtype(Integer.parseInt(operationType));
        smsRecord.setParamJson(paramJson);

        smsRecord.setTemplateId(smsTemplate.getTemplateId());
        smsRecord.setSmsSign(smsTemplate.getSmsSign());
        smsRecord.setSmsMsg(smsTemplate.getTemplateContext());

        smsRecord.setIp(ip);
        smsRecord.setOutId(outId);
        boolean saveFlag = save(smsRecord);
        if (saveFlag) {
            return smsRecord;
        } else {
            return null;
        }
    }

    @Override
    public ResponseVo preSendCode() {

        JSONObject jsonObject = new JSONObject();

        // 当前发送短信是否需要验证码
        String redisKey = RedisKeyConstant.IMAGE_LOGIN_FLAG;
        if (stringRedisTemplate.hasKey(redisKey)){
            jsonObject.put("imageLoginFlag", true);
        }else{
            jsonObject.put("imageLoginFlag", false);
        }

        return new ResponseVo(AppRspCodeConstant.SUCCESS, jsonObject);
    }

}
